package com.mdxq.mall.filter;

import cn.hutool.jwt.JWT;
import cn.hutool.jwt.JWTUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.time.LocalDateTime;
import java.util.List;

@Component
@ConfigurationProperties(prefix = "spring.cloud.gateway.global-filter")
public class AuthFilter implements GlobalFilter {
    List<String> whiteListPaths;

    public void setWhiteListPaths(List<String> whiteListPaths) {
        this.whiteListPaths = whiteListPaths;
    }

    //在 filter 方法中，我们可以利用 exchange(交换机) 来获取请求的路径，如 exchange.getRequest().getPath().value();
    // 并将其存储在 path 变量中。然后可以将这个 path 与 whiteListPaths 中的元素进行比较，以决定如何处理该请求

    @Autowired
    private RedisTemplate redisTemplate;
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();//获取请求对象
        String path = request.getPath().value();//获取请求路径
        //在白名单中，放行
        if (whiteListPaths.contains(path)) {
            //当前过滤器放行，进入到下个过滤器
            return chain.filter(exchange);
        }
        //get("Authorization")返回的一定是个列表，从列表中取出第0项
        List<String> list = request.getHeaders().get("Authorization");
        //未携带令牌
        ServerHttpResponse response = exchange.getResponse();
        if (list == null || list.size() == 0) {
            response.setRawStatusCode(401);//认证失败，返回未授权
            return response.setComplete();
        }
        //取出令牌
        String token = list.get(0);
        //判断缓存里有没有token
        if (!redisTemplate.hasKey(token)){
            response.setRawStatusCode(401);//认证失败，返回未授权
            return response.setComplete();
        }
        try {
            if (JWTUtil.verify(token, "md-mall-0112".getBytes())) {//令牌合法
                JWT jwt = JWTUtil.parseToken(token);
                long iat = Long.valueOf(jwt.getPayload("iat").toString());//签发时间
                long exp = Long.valueOf(jwt.getPayload("exp").toString());//有效时长
                long now = System.currentTimeMillis()/1000;
                if (iat + exp > now) {//未过期
                    return chain.filter(exchange);//认证通过放行
                } else {
                    response.setRawStatusCode(401);//令牌过期
                }
            } else {
                response.setRawStatusCode(401);//认证未通过
            }
        } catch (Exception e) {
            //令牌篡改或者伪造，导致令牌出错
            response.setRawStatusCode(401);
        }
        //结束当前的过滤链，不再往下执行
        return response.setComplete();
    }
}
